package com.example.openglesex;

import java.nio.ByteBuffer;
import java.nio.ByteOrder;
import java.nio.FloatBuffer;
import java.nio.IntBuffer;
import java.util.ArrayList;
import java.util.List;

import javax.microedition.khronos.egl.EGLConfig;
import javax.microedition.khronos.opengles.GL10;
import javax.microedition.khronos.opengles.GL11;

import android.content.Context;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.opengl.GLSurfaceView.Renderer;
import android.opengl.GLU;
import android.opengl.GLUtils;
import android.opengl.Matrix;

public class GlRenderer implements Renderer {

	private Context context;
	private CubeDrawAr mCube = new CubeDrawAr(1);
	// private int bkTexture = 1000;
	private Icon mIcon = new Icon(-2, 2, 2, -2, 0);
	private boolean isFirstframe = true;
	public float mAngleY;
	public float mAngleX;
	public float mWidth;
	public float mHeight;

	private int[] mView = new int[4];
	private float[] mProjectMat = new float[16];
	private float[] mOrigin = new float[4];
	private float[] mDirection = new float[4];
	private float[] mModelViewMat = new float[16];
	private float[] mViewMat = new float[16];
	private float[] mInv = new float[16];
	private FloatBuffer mRayBuf = IBufferFactory.newFloatBuffer(6);

	public GlRenderer(Context context) {
		this.context = context;
	}

	public void onSurfaceCreated(GL10 gl, EGLConfig config) {
		gl.glShadeModel(GL10.GL_SMOOTH);
		gl.glClearColor(1, 1, 1, 0);

		gl.glClearDepthf(1.0f);
		gl.glEnable(GL10.GL_DEPTH_TEST);
		gl.glDepthFunc(GL10.GL_LEQUAL);

		// gl.glColor4f(1f, 1f, 1f, 0.5f);
		// gl.glBlendFunc(GL10.GL_SRC_ALPHA, GL10.GL_ONE_MINUS_SRC_ALPHA);

		gl.glHint(GL10.GL_PERSPECTIVE_CORRECTION_HINT, GL10.GL_NICEST);

		gl.glDisable(GL10.GL_CULL_FACE);
		initTexture(gl);

	}

	private void initTexture(GL10 gl) {
		// create texture
		gl.glEnable(GL10.GL_TEXTURE_2D);
		IntBuffer texturesBuffer = IntBuffer.allocate(7);
		gl.glGenTextures(7, texturesBuffer);

		List<Bitmap> bitmaps = new ArrayList<Bitmap>();
		bitmaps.add(Utils.getTextureFromBitmapResource(this.context, R.drawable.crate));
		bitmaps.add(Utils.getTextureFromBitmapResource(this.context, R.drawable.star));
		bitmaps.add(Utils.getTextureFromBitmapResource(this.context, R.drawable.gongziya));
		bitmaps.add(Utils.getTextureFromBitmapResource(this.context, R.drawable.nehe));
		bitmaps.add(Utils.getTextureFromBitmapResource(this.context, R.drawable.glass));
		bitmaps.add(Utils.getTextureFromBitmapResource(this.context, R.drawable.gongziya));

		Bitmap b = BitmapFactory.decodeResource(this.context.getResources(), R.drawable.bk);
		Bitmap b2 = Bitmap.createScaledBitmap(b, 512, 512, true);
		b.recycle();
		bitmaps.add(b2);

		for (int i = 0; i < 7; i++) {
			gl.glBindTexture(GL10.GL_TEXTURE_2D, texturesBuffer.get(i));

			// setup texture parameters
			gl.glTexParameterx(GL10.GL_TEXTURE_2D, GL10.GL_TEXTURE_MAG_FILTER, GL10.GL_LINEAR);
			gl.glTexParameterx(GL10.GL_TEXTURE_2D, GL10.GL_TEXTURE_MIN_FILTER, GL10.GL_LINEAR);
			gl.glTexParameterx(GL10.GL_TEXTURE_2D, GL10.GL_TEXTURE_WRAP_S, GL10.GL_CLAMP_TO_EDGE);
			gl.glTexParameterx(GL10.GL_TEXTURE_2D, GL10.GL_TEXTURE_WRAP_T, GL10.GL_CLAMP_TO_EDGE);

			// set the texture
			// Bitmap texture =
			// BitmapFactory.decodeResource(context.getResources(),
			// R.drawable.nehe);
			GLUtils.texImage2D(GL10.GL_TEXTURE_2D, 0, bitmaps.get(i), 0);
			bitmaps.get(i).recycle();
		}
		mCube.mTextures = texturesBuffer.array();
		mIcon.mTexture = texturesBuffer.get(6);
	}

	public void onDrawFrame(GL10 gl) {
		gl.glClear(GL10.GL_COLOR_BUFFER_BIT | GL10.GL_DEPTH_BUFFER_BIT);
		gl.glMatrixMode(GL10.GL_MODELVIEW);

		if (isFirstframe == true) { // 第一祯先做好平移，作为以后旋转的基础
			gl.glLoadIdentity();
			gl.glTranslatef(0, 0, -8);
			((GL11) gl).glGetFloatv(GL11.GL_MODELVIEW_MATRIX, mViewMat, 0);
			gl.glPushMatrix();
			isFirstframe = false;
		}

		// float[] modelview = new float[16] ;
		((GL11) gl).glGetFloatv(GL11.GL_MODELVIEW_MATRIX, mModelViewMat, 0);

		float[] xAxis = { 1, 0, 0, 0 };
		float[] yAxis = { 0, 1, 0, 0 };
		Matrix.invertM(mInv, 0, mModelViewMat, 0);
		Matrix.multiplyMV(xAxis, 0, mInv, 0, xAxis, 0);
		Matrix.multiplyMV(yAxis, 0, mInv, 0, yAxis, 0);

		gl.glRotatef(mAngleY, yAxis[0], yAxis[1], yAxis[2]);
		gl.glRotatef(mAngleX, xAxis[0], xAxis[1], xAxis[2]);

		gl.glEnableClientState(GL10.GL_VERTEX_ARRAY);
		gl.glEnableClientState(GL10.GL_TEXTURE_COORD_ARRAY);

		mCube.draw(gl);

		gl.glDisable(GL10.GL_DEPTH_TEST);

//		// 画射线
//		gl.glPushMatrix();
//	    gl.glLoadIdentity();
//		gl.glLineWidth(10.0f);
//		gl.glColor4f(1.0f, 0.0f, 0.0f, 1.0f);
//		gl.glVertexPointer(3, GL10.GL_FLOAT, 0, mRayBuf);
//		gl.glDrawArrays(GL10.GL_LINES, 0, 2);
//		gl.glLineWidth(1.0f);
//		gl.glColor4f(1.0f, 1.0f, 1.0f, 1.0f);
//		gl.glPopMatrix();

		gl.glEnable(GL10.GL_BLEND);
		gl.glBlendFunc(GL10.GL_SRC_ALPHA, GL10.GL_ONE_MINUS_SRC_ALPHA);
		mIcon.draw(gl);
		gl.glEnable(GL10.GL_DEPTH_TEST);
		gl.glDisable(GL10.GL_BLEND);

		gl.glDisableClientState(GL10.GL_VERTEX_ARRAY);
		gl.glDisableClientState(GL10.GL_TEXTURE_COORD_ARRAY);

		mAngleY = 0;
		mAngleX = 0;
	}

	public void onSurfaceChanged(GL10 gl, int width, int height) {
		// avoid division by zero
		if (height == 0)
			height = 1;
		// draw on the entire screen
		gl.glViewport(0, 0, width, height);
		mView[0] = 0;
		mView[1] = 0;
		mView[2] = width;
		mView[3] = height;
		// setup projection matrix
		gl.glMatrixMode(GL10.GL_PROJECTION);
		gl.glLoadIdentity();
		GLU.gluPerspective(gl, 45.0f, (float) width / (float) height, 1.0f, 10.0f);
		((GL11) gl).glGetFloatv(GL11.GL_PROJECTION_MATRIX, mProjectMat, 0);
		this.mHeight = height;
		this.mWidth = width;
	}

	private static ByteBuffer getOrderBB(int capacity) {
		ByteBuffer bb = ByteBuffer.allocateDirect(capacity);
		bb.order(ByteOrder.nativeOrder());
		return bb;
	}

	public void computRay(float x, float y) {

		float openglY = this.mHeight - y;
		GLU.gluUnProject(x, openglY, 0, mModelViewMat, 0, mProjectMat, 0, mView, 0, mOrigin, 0);
		GLU.gluUnProject(x, openglY, 1, mModelViewMat, 0, mProjectMat, 0, mView, 0, mDirection, 0);

		mRayBuf = IBufferFactory.newFloatBuffer(6);

		mOrigin[0] = mOrigin[0] / mOrigin[3];
		mOrigin[1] = mOrigin[1] / mOrigin[3];
		mOrigin[2] = mOrigin[2] / mOrigin[3];
		mDirection[0] = mDirection[0] / mDirection[3];
		mDirection[1] = mDirection[1] / mDirection[3];
		mDirection[2] = mDirection[2] / mDirection[3];

		mRayBuf.put(mOrigin[0]);
		mRayBuf.put(mOrigin[1]);
		mRayBuf.put(mOrigin[2]);

		mRayBuf.put(mDirection[0]);
		mRayBuf.put(mDirection[1]);
		mRayBuf.put(mDirection[2]);
		mRayBuf.position(0);
		
		mCube.intersect(mOrigin, mDirection);

	}
}
